/* gf_basic_tester.c
 * James S. Plank

Galois.tar - Fast Galois Field Arithmetic Library in C/C++
Copright (C) 2007 James S. Plank

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

James S. Plank
Department of Computer Science
University of Tennessee
Knoxville, TN 37996
plank@cs.utk.edu

 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "galois.h"
#include "galois_add.h"
#include <sys/time.h>

#define BUFSIZE (5000000)
#define S_BUFSIZE (4096)
#define DEFAULT 1
#define MULT 2
#define LOG 3
#define SHIFT 4
#define SPLITW8 5

#define COMP2 6
#define COMP4 7
#define SCOMP2 8
#define LAZYTABLE8 9
#define LAZYTABLE16 10
#define TEST 11
#define LAZYSPLIT 12

#define COMP22 13

extern int printer;
int printer;

void usage(char *s)
{
  fprintf(stderr, "usage: gf_basic_tester w default|multtable|logtable|shift|splitw8|comp2|comp4|lazytable8|lazytable16 ntrials-for-correctness\n");
  if (s != NULL) fprintf(stderr, "%s\n", s);
  exit(1);
}

main(int argc, char **argv)
{
  unsigned int w, alltype, nt, i, x, y, z, top, elt, q1, q2;
  unsigned int *b1, *b2;
  unsigned int *ib1, *ib2, *ib3;
  unsigned short *sb1, *sb2, *sb3;
  struct timeval t1, t2;
  struct timezone tz;
  long t0, now;
  double total, tsec;
  unsigned char *cb1, *cb2, *cb3;
  int mtype;

  if (argc != 4) usage(NULL);

  w = atoi(argv[1]);
  if (w <= 0 || w > 32) usage("w must be in [1,32]\n");

  
/*  Table initialization */
  if (strcmp(argv[2], "default") == 0) {
    mtype = DEFAULT;
  } else if (strcmp(argv[2], "multtable") == 0) {
    mtype = MULT;
    if (galois_create_mult_tables(w) != 0) {
      printf("Cannot create multiplication tables for w = %d\n", w);
      exit(0);
    }
  } else if (strcmp(argv[2], "logtable") == 0) {
    if (galois_create_log_tables(w) != 0) {
      printf("Cannot create log tables for w = %d\n", w);
      exit(0);
    }
    mtype = LOG;
  } else if (strcmp(argv[2], "shift") == 0) {
    mtype = SHIFT;
  } else if (strcmp(argv[2], "splitw8") == 0) {
    mtype = SPLITW8;
    if (w != 32) {
      fprintf(stderr, "Splitw8 is only valid for w = 32\n");
      exit(1);
    }
    if (galois_create_split_w8_tables() != 0) {
      printf("Cannot create split_w8 tables for w = %d\n", w);
      exit(0);
    }
  } else if (strcmp(argv[2], "comp2") == 0) {
		mtype = COMP2;
	} else if (strcmp(argv[2], "comp4") == 0) {
		mtype = COMP4;
	} else if (strcmp(argv[2], "scomp2") == 0) {
		if (w != 32) { usage("for scomp2, 32 is the only valid value for w\n"); }
		mtype = SCOMP2;
	} else if (strcmp(argv[2], "lazytable8") == 0) {
    if (galois_create_mult_tables(w) != 0) {
      printf("Cannot create multiplication tables for w = %d\n", w);
      exit(0);
    }
		mtype = LAZYTABLE8;
	} else if (strcmp(argv[2], "lazytable16") == 0) {
    if (galois_create_log_tables(w) != 0) {
      printf("Cannot create log tables for w = %d\n", w);
      exit(0);
    }
		mtype = LAZYTABLE16;
	} else if (strcmp(argv[2], "test") == 0) {
		if (galois_create_split_w8_tables() != 0) {
			printf("Cannot create split_w8 tables for w = %d\n", w);
			exit(0);
		}
		mtype = TEST;
	} else if (strcmp(argv[2], "lazysplit") == 0) {
		if (!(w == 32 || w == 64)) {
			fprintf(stderr, "Lazy split tables are only implemented for w == 32 and w == 64");
			exit(1);
		}
		mtype = LAZYSPLIT;
	} else if (strcmp(argv[2], "comp22") == 0) {
		mtype = COMP22;
	} else {
		usage("arg 2 must be default, multtable, logtable, shift, splitw8, comop2, comp4, scomp2, lazytable8, lazytable16, lazysplit\n");
	}
 
  nt = atoi(argv[3]);

  t0 = time(0);
  srand48(0); 
  printf("W: %d\n", w);
  printf("Method: %s\n", argv[2]);
  printf("Seeding random number generator with %u\n", t0);
  
  top = (1 << w);

  b1 = (unsigned int *) malloc(sizeof(unsigned int) * S_BUFSIZE);
  b2 = (unsigned int *) malloc(sizeof(unsigned int) * S_BUFSIZE);
  if (w < 32 ) {
    for (i = 0; i < S_BUFSIZE; i++) b1[i] = lrand48() % top;
    for (i = 0; i < S_BUFSIZE; i++) b2[i] = lrand48() % top;
  } else {
    for (i = 0; i < S_BUFSIZE; i++) b1[i] = lrand48();
    for (i = 0; i < S_BUFSIZE; i++) b2[i] = lrand48();
  }

  if (w == 8 || w == 16 || w == 32) {
    cb1 = (unsigned char *) malloc(sizeof(unsigned char) * BUFSIZE);
    cb2 = (unsigned char *) malloc(sizeof(unsigned char) * BUFSIZE);
    cb3 = (unsigned char *) malloc(sizeof(unsigned char) * BUFSIZE);
    for (i = 0; i < BUFSIZE; i++) cb1[i] = lrand48() % 256;
    for (i = 0; i < BUFSIZE; i++) cb2[i] = lrand48() % 256;
  }

if (mtype != TEST && mtype != LAZYSPLIT && mtype != COMP22) {
  printf("Doing %u trials for single-operation correctness.\n", nt);
  for (i = 0; i < nt; i++) {
    if (w < 32) {
      x = lrand48()%(top-1)+1;
      y = lrand48()%(top-1)+1;
    } else {
      for (x = 0; x == 0; x = lrand48()) ;
      for (y = 0; y == 0; y = lrand48()) ;
    }
    switch (mtype) {
      case DEFAULT: z = galois_single_multiply(x, y, w); 
                    q1 = galois_single_divide(z, x, w); 
                    q2 = galois_single_divide(z, y, w); 
                    break;
      case MULT:    z = galois_multtable_multiply(x, y, w);
                    q1 = galois_multtable_divide(z, x, w); 
                    q2 = galois_multtable_divide(z, y, w); 
                    break;
			case LAZYTABLE8: 
										z = galois_multtable_multiply(x, y, w);
										q1 = galois_multtable_divide(z, x, w);
										q2 = galois_multtable_divide(z, y, w);
										break;
			case LOG:			z = galois_logtable_multiply(x, y, w);
										q1 = galois_logtable_divide(z, x, w); 
										q2 = galois_logtable_divide(z, y, w); 
										break;
			case LAZYTABLE16:     z = galois_logtable_multiply(x, y, w);
										q1 = galois_logtable_divide(z, x, w);
										q2 = galois_logtable_divide(z, y, w);
			case SHIFT:   z = galois_shift_multiply(x, y, w);
										q1 = galois_shift_divide(z, x, w); 
										q2 = galois_shift_divide(z, y, w); 
										break;
			case SPLITW8: z = galois_split_w8_multiply(x, y);
										q1 = galois_shift_divide(z, x, w); 
										q2 = galois_shift_divide(z, y, w); 
										break;
			case COMP2:		z = galois_composite_multiply_k2(x, y, w);
										q1 = galois_composite_divide_k2(z, x, w);
										q2 = galois_composite_divide_k2(z, y, w);
										break;
			case COMP4:		z = galois_composite_multiply_k4(x, y, w);
										q1 = galois_composite_divide_k4(z, x, w);
										q2 = galois_composite_divide_k4(z, y, w);
										break;
			case SCOMP2:	z = galois_composite_multiply_k2(x, y, w);
										q1 = galois_composite_divide_k2(z, x, w);
										q2 = galois_composite_divide_k2(z, y, w);
										break;
		}
		if (q1 != y) {
			fprintf(stderr, "Failed test: %u * %u = %u, but %u / %u = %u\n",
					x, y, z, z, x, q1);
			exit(1);
		}
		if (q2 != x) {
			fprintf(stderr, "Failed test: %u * %u = %u, but %u / %u = %u\n",
					y, x, z, z, y, q2);
			exit(1);
		}
		if (!(mtype == COMP2 || mtype == COMP4 || mtype == SCOMP2)) {
			z = galois_inverse(x, w);
			q1 = galois_inverse(z, w);
		} else if (mtype == COMP2 || mtype == SCOMP2) {
			z = galois_composite_inverse_k2(x, w);
			q1 = galois_composite_inverse_k2(z, w);
		} else if (mtype == COMP4) {
			z = galois_composite_inverse_k4(x, w);
			q1 = galois_composite_inverse_k4(z, w);
		}
		if (q1 != x) {
			fprintf(stderr, "Failed test: gf_inverse(%u) = %u, but gf_inverse(%u) = %u\n",
					x, z, z, q1);
			exit(1);
		}
	}
	printf("Passed Single-Operations Correctness Tests.\n");
	printf("\n");
	}

	if (w == 8 && mtype == COMP2) {
		printf("Doing galois_composite_w08_region_mult_k2 correctness test.\n");
		for (x = 0; x < 10; x++) {

			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_composite_w08_region_mult_k2( cb1, elt, BUFSIZE,  cb3, 0);
			for (i = 0; i < BUFSIZE; i++) {
				if (galois_composite_multiply_k2(cb1[i], elt, w) != cb3[i]) {
					printf("Failed test (r2 != NULL, add == 0): %u * %u = %u, but it is %u in cb3\n", 
							cb1[i], elt, galois_composite_multiply_k2(cb1[i], elt, w), cb3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_composite_w08_region_mult_k2( cb1, elt, BUFSIZE,  cb3, 0);
			elt = galois_composite_divide_k2(1, elt, w);
			galois_composite_w08_region_mult_k2( cb3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE; i++) {
				if (cb1[i] != cb3[i]) {
					printf("Failed test (r2 == NULL): %u != %u\n", cb1[i], cb3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48()%top);
			for (i = 0; i < BUFSIZE; i++) cb3[i] = cb2[i];
			galois_composite_w08_region_mult_k2( cb1, elt, BUFSIZE,  cb3, 1);
			for (i = 0; i < BUFSIZE; i++) {
				if (cb3[i] != (cb2[i] ^ galois_composite_multiply_k2(cb1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1): (%u * %u) ^ %u = %u.  cb3 = %u\n", 
							cb1[i], elt, cb2[i], (galois_composite_multiply_k2(cb1[i], elt, w)^cb2[i]), cb3[i]);
					exit(1);
				}
			}
		}
		galois_composite_w08_region_mult_k2( cb1, 0, BUFSIZE,  cb3, 0);
		for (i = 0; i < BUFSIZE; i++) {
			if (cb3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, cb3[i]);
				exit(1);
			}
		}
		printf("Passed galois_composite_w08_region_mult_k2 correctness test.\n");
		printf("\n");
	}

	if (w == 8 && mtype == LOG) {
		printf("Doing galois_w08_log_region_multiply correctness test.\n");
		for (x = 0; x < 10; x++) {

			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w08_log_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 0);
			for (i = 0; i < BUFSIZE; i++) {
				if (galois_single_multiply(cb1[i], elt, w) != cb3[i]) {
					printf("Failed test (r2 != NULL, add == 0): %u * %u = %u, but it is %u in cb3\n", 
							cb1[i], elt, galois_single_multiply(cb1[i], elt, w), cb3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w08_log_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 0);
			elt = galois_single_divide(1, elt, w);
			galois_w08_log_region_multiply((unsigned char *) cb3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE; i++) {
				if (cb1[i] != cb3[i]) {
					printf("Failed test (r2 == NULL): %u != %u\n", cb1[i], cb3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48()%top);
			for (i = 0; i < BUFSIZE; i++) cb3[i] = cb2[i];
			galois_w08_log_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 1);
			for (i = 0; i < BUFSIZE; i++) {
				if (cb3[i] != (cb2[i] ^ galois_single_multiply(cb1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1): (%u * %u) ^ %u = %u.  cb3 = %u\n", 
							cb1[i], elt, cb2[i], (galois_single_multiply(cb1[i], elt, w)^cb2[i]), cb3[i]);
					exit(1);
				}
			}
		}
		galois_w08_log_region_multiply((unsigned char *) cb1, 0, BUFSIZE, (unsigned char *) cb3, 0);
		for (i = 0; i < BUFSIZE; i++) {
			if (cb3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, cb3[i]);
				exit(1);
			}
		}
		printf("Passed galois_w08_log_region_multiply correctness test.\n");
		printf("\n");
	}

	if (w == 8 && mtype == LAZYTABLE8) {
		printf("Doing galois_w08_lazytable_region_multiply correctness test.\n");
		for (x = 0; x < 10; x++) {

			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w08_lazytable_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 0);
			for (i = 0; i < BUFSIZE; i++) {
				if (galois_single_multiply(cb1[i], elt, w) != cb3[i]) {
					printf("Failed test (r2 != NULL, add == 0): %u * %u = %u, but it is %u in cb3\n", 
							cb1[i], elt, galois_single_multiply(cb1[i], elt, w), cb3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w08_lazytable_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 0);
			elt = galois_single_divide(1, elt, w);
			galois_w08_lazytable_region_multiply((unsigned char *) cb3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE; i++) {
				if (cb1[i] != cb3[i]) {
					printf("Failed test (r2 == NULL): %u != %u\n", cb1[i], cb3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48()%top);
			for (i = 0; i < BUFSIZE; i++) cb3[i] = cb2[i];
			galois_w08_lazytable_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 1);
			for (i = 0; i < BUFSIZE; i++) {
				if (cb3[i] != (cb2[i] ^ galois_single_multiply(cb1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1): (%u * %u) ^ %u = %u.  cb3 = %u\n", 
							cb1[i], elt, cb2[i], (galois_single_multiply(cb1[i], elt, w)^cb2[i]), cb3[i]);
					exit(1);
				}
			}
		}
		galois_w08_lazytable_region_multiply((unsigned char *) cb1, 0, BUFSIZE, (unsigned char *) cb3, 0);
		for (i = 0; i < BUFSIZE; i++) {
			if (cb3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, cb3[i]);
				exit(1);
			}
		}
		printf("Passed galois_w08_lazytable_region_multiply correctness test.\n");
		printf("\n");
	}

	if (w == 8 && mtype == DEFAULT) {
		printf("Doing galois_w08_region_multiply correctness test.\n");
		for (x = 0; x < 10; x++) {

			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w08_region_multiply((char *) cb1, elt, BUFSIZE, (char *) cb3, 0);
			for (i = 0; i < BUFSIZE; i++) {
				if (galois_single_multiply(cb1[i], elt, w) != cb3[i]) {
					printf("Failed test (r2 != NULL, add == 0): %u * %u = %u, but it is %u in cb3\n", 
							cb1[i], elt, galois_single_multiply(cb1[i], elt, w), cb3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w08_region_multiply((char *) cb1, elt, BUFSIZE, (char *) cb3, 0);
			elt = galois_single_divide(1, elt, w);
			galois_w08_region_multiply((char *) cb3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE; i++) {
				if (cb1[i] != cb3[i]) {
					printf("Failed test (r2 == NULL): %u != %u\n", cb1[i], cb3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48()%top);
			for (i = 0; i < BUFSIZE; i++) cb3[i] = cb2[i];
			galois_w08_region_multiply((char *) cb1, elt, BUFSIZE, (char *) cb3, 1);
			for (i = 0; i < BUFSIZE; i++) {
				if (cb3[i] != (cb2[i] ^ galois_single_multiply(cb1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1): (%u * %u) ^ %u = %u.  cb3 = %u\n", 
							cb1[i], elt, cb2[i], (galois_single_multiply(cb1[i], elt, w)^cb2[i]), cb3[i]);
					exit(1);
				}
			}
		}
		galois_w08_region_multiply((char *) cb1, 0, BUFSIZE, (char *) cb3, 0);
		for (i = 0; i < BUFSIZE; i++) {
			if (cb3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, cb3[i]);
				exit(1);
			}
		}
		printf("Passed galois_w08_region_multiply correctness test.\n");
		printf("\n");
	}

	if (w == 16 && mtype == LAZYTABLE16) {
		printf("Doing galois_w16_lazytable_region_multiply correctness test.\n");
		sb1 = (unsigned short *) cb1;
		sb2 = (unsigned short *) cb2;
		sb3 = (unsigned short *) cb3;
		for (x = 0; x < 10; x++) {

			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w16_lazytable_region_multiply((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 0);
			for (i = 0; i < BUFSIZE/2; i++) {
				if (galois_single_multiply(sb1[i], elt, w) != sb3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in sb3\n", 
							i, sb1[i], elt, galois_single_multiply(sb1[i], elt, w), sb3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w16_lazytable_region_multiply((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 0);
			elt = galois_single_divide(1, elt, w);
			galois_w16_lazytable_region_multiply((unsigned char *) sb3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/2; i++) {
				if (sb1[i] != sb3[i]) {
					printf("Failed test (r2 == NULL): %u != %u\n", sb1[i], sb3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48()%top);
			for (i = 0; i < BUFSIZE/2; i++) sb3[i] = sb2[i];
			galois_w16_lazytable_region_multiply((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 1);
			for (i = 0; i < BUFSIZE/2; i++) {
				if (sb3[i] != (sb2[i] ^ galois_single_multiply(sb1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  sb3 = %u\n", 
							i, sb1[i], elt, sb2[i], (galois_single_multiply(sb1[i], elt, w)^sb2[i]), sb3[i]);
					exit(1);
				}
			}
		}
		galois_w16_lazytable_region_multiply((unsigned char *) sb1, 0, BUFSIZE, (unsigned char *) sb3, 0);
		for (i = 0; i < BUFSIZE/2; i++) {
			if (sb3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, sb3[i]);
				exit(1);
			}
		}
		printf("Passed galois_w16_lazytable_region_multiply correctness test.\n");
		printf("\n");
	}

	if (w == 16 && mtype == COMP2) {
		printf("Doing galois_composite_w16_region_mult_k2 correctness test.\n");
		sb1 = (unsigned short *) cb1;
		sb2 = (unsigned short *) cb2;
		sb3 = (unsigned short *) cb3;
		for (x = 0; x < 10; x++) {

			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_composite_w16_region_mult_k2((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 0);
			for (i = 0; i < BUFSIZE/2; i++) {
				if (galois_composite_multiply_k2(sb1[i], elt, w) != sb3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in sb3\n", 
							i, sb1[i], elt, galois_composite_multiply_k2(sb1[i], elt, w), sb3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_composite_w16_region_mult_k2((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 0);
			elt = galois_composite_divide_k2(1, elt, w);
			galois_composite_w16_region_mult_k2((unsigned char *) sb3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/2; i++) {
				if (sb1[i] != sb3[i]) {
					printf("Failed test (r2 == NULL): %u != %u\n", sb1[i], sb3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48()%top);
			for (i = 0; i < BUFSIZE/2; i++) sb3[i] = sb2[i];
			galois_composite_w16_region_mult_k2((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 1);
			for (i = 0; i < BUFSIZE/2; i++) {
				if (sb3[i] != (sb2[i] ^ galois_composite_multiply_k2(sb1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  sb3 = %u\n", 
							i, sb1[i], elt, sb2[i], (galois_composite_multiply_k2(sb1[i], elt, w)^sb2[i]), sb3[i]);
					exit(1);
				}
			}
		}
		galois_composite_w16_region_mult_k2((unsigned char *) sb1, 0, BUFSIZE, (unsigned char *) sb3, 0);
		for (i = 0; i < BUFSIZE/2; i++) {
			if (sb3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, sb3[i]);
				exit(1);
			}
		}
		printf("Passed galois_composite_w16_region_mult_k2 correctness test.\n");
		printf("\n");
	}

	if (w == 16 && mtype == DEFAULT) {
		printf("Doing galois_w16_region_multiply correctness test.\n");
		sb1 = (unsigned short *) cb1;
		sb2 = (unsigned short *) cb2;
		sb3 = (unsigned short *) cb3;
		for (x = 0; x < 10; x++) {

			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w16_region_multiply((char *) sb1, elt, BUFSIZE, (char *) sb3, 0);
			for (i = 0; i < BUFSIZE/2; i++) {
				if (galois_single_multiply(sb1[i], elt, w) != sb3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in sb3\n", 
							i, sb1[i], elt, galois_single_multiply(sb1[i], elt, w), sb3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48()%top);
			galois_w16_region_multiply((char *) sb1, elt, BUFSIZE, (char *) sb3, 0);
			elt = galois_single_divide(1, elt, w);
			galois_w16_region_multiply((char *) sb3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/2; i++) {
				if (sb1[i] != sb3[i]) {
					printf("Failed test (r2 == NULL): %u != %u\n", sb1[i], sb3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48()%top);
			for (i = 0; i < BUFSIZE/2; i++) sb3[i] = sb2[i];
			galois_w16_region_multiply((char *) sb1, elt, BUFSIZE, (char *) sb3, 1);
			for (i = 0; i < BUFSIZE/2; i++) {
				if (sb3[i] != (sb2[i] ^ galois_single_multiply(sb1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  sb3 = %u\n", 
							i, sb1[i], elt, sb2[i], (galois_single_multiply(sb1[i], elt, w)^sb2[i]), sb3[i]);
					exit(1);
				}
			}
		}
		galois_w16_region_multiply((char *) sb1, 0, BUFSIZE, (char *) sb3, 0);
		for (i = 0; i < BUFSIZE/2; i++) {
			if (sb3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, sb3[i]);
				exit(1);
			}
		}
		printf("Passed galois_w16_region_multiply correctness test.\n");
		printf("\n");
	}

if (mtype == COMP22 && w == 32) {
		printf("Doing galois_w32_composite_region_mult_k22 correctness test.\n");
		ib1 = (unsigned int *) cb1;
		ib2 = (unsigned int *) cb2;
		ib3 = (unsigned int *) cb3;
		for (x = 0; x < 10; x++) {
			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_w32_composite_region_mult_k22((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				printer = 1;
				if (galois_composite_multiply_k22(ib1[i], elt, w) != ib3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in ib3\n", 
							i, ib1[i], elt, galois_composite_multiply_k22(ib1[i], elt, w), ib3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_w32_composite_region_mult_k22((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			elt = galois_composite_divide_k22(1, elt, w);
			galois_w32_composite_region_mult_k22((unsigned char *) ib3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib1[i] != ib3[i]) {
					printf("Failed test (r2 == NULL): Byte %d (0x%x): %u != %u\n", i, ib3+i, ib1[i], ib3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48());
			for (i = 0; i < BUFSIZE/4; i++) ib3[i] = ib2[i];
			galois_w32_composite_region_mult_k22((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 1);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib3[i] != (ib2[i] ^ galois_composite_multiply_k22(ib1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  ib3 = %u\n", 
							i, ib1[i], elt, ib2[i], (galois_composite_multiply_k22(ib1[i], elt, w)^ib2[i]), ib3[i]);
					exit(1);
				}
			}
		}
		galois_w32_composite_region_mult_k22((unsigned char *) ib1, 0, BUFSIZE, (unsigned char *) ib3, 0);
		for (i = 0; i < BUFSIZE/4; i++) {
			if (ib3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, ib3[i]);
				exit(1);
			}
		}
		printf("Passed galois_w32_composite_region_mult_k22 correctness test.\n");
		printf("\n");
	}

	if (w == 32 && mtype == COMP4) {
		printf("Doing galois_composite_w32_region_mult_k4 correctness test.\n");
		ib1 = (unsigned int *) cb1;
		ib2 = (unsigned int *) cb2;
		ib3 = (unsigned int *) cb3;
		for (x = 0; x < 10; x++) {
			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_composite_w32_region_mult_k4((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				printer = 1;
				if (galois_composite_multiply_k4(ib1[i], elt, w) != ib3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in ib3\n", 
							i, ib1[i], elt, galois_composite_multiply_k4(ib1[i], elt, w), ib3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_composite_w32_region_mult_k4((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			elt = galois_composite_divide_k4(1, elt, w);
			galois_composite_w32_region_mult_k4((unsigned char *) ib3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib1[i] != ib3[i]) {
					printf("Failed test (r2 == NULL): Byte %d (0x%x): %u != %u\n", i, ib3+i, ib1[i], ib3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48());
			for (i = 0; i < BUFSIZE/4; i++) ib3[i] = ib2[i];
			galois_composite_w32_region_mult_k4((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 1);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib3[i] != (ib2[i] ^ galois_composite_multiply_k4(ib1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  ib3 = %u\n", 
							i, ib1[i], elt, ib2[i], (galois_composite_multiply_k4(ib1[i], elt, w)^ib2[i]), ib3[i]);
					exit(1);
				}
			}
		}
		galois_composite_w32_region_mult_k4((unsigned char *) ib1, 0, BUFSIZE, (unsigned char *) ib3, 0);
		for (i = 0; i < BUFSIZE/4; i++) {
			if (ib3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, ib3[i]);
				exit(1);
			}
		}
		printf("Passed galois_composite_w32_region_mult_k4 correctness test.\n");
		printf("\n");
	}

	if (mtype == SCOMP2 && w == 32) {
		printf("Doing galois_split_composite_w32_region_mult_k2 correctness test.\n");
		ib1 = (unsigned int *) cb1;
		ib2 = (unsigned int *) cb2;
		ib3 = (unsigned int *) cb3;
		for (x = 0; x < 10; x++) {
			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_split_composite_w32_region_mult_k2((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				printer = 1;
				if (galois_composite_multiply_k2(ib1[i], elt, w) != ib3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in ib3\n", 
							i, ib1[i], elt, galois_composite_multiply_k2(ib1[i], elt, w), ib3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_split_composite_w32_region_mult_k2((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			elt = galois_composite_divide_k2(1, elt, w);
			galois_split_composite_w32_region_mult_k2((unsigned char *) ib3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib1[i] != ib3[i]) {
					printf("Failed test (r2 == NULL): Byte %d (0x%x): %u != %u\n", i, ib3+i, ib1[i], ib3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48());
			for (i = 0; i < BUFSIZE/4; i++) ib3[i] = ib2[i];
			galois_split_composite_w32_region_mult_k2((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 1);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib3[i] != (ib2[i] ^ galois_composite_multiply_k2(ib1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  ib3 = %u\n", 
							i, ib1[i], elt, ib2[i], (galois_composite_multiply_k2(ib1[i], elt, w)^ib2[i]), ib3[i]);
					exit(1);
				}
			}
		}
		galois_split_composite_w32_region_mult_k2((unsigned char *) ib1, 0, BUFSIZE, (unsigned char *) ib3, 0);
		for (i = 0; i < BUFSIZE/4; i++) {
			if (ib3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, ib3[i]);
				exit(1);
			}
		}
		printf("Passed galois_split_composite_w32_region_mult_k2 correctness test.\n");
		printf("\n");
	}

	if (w == 32 && mtype == COMP2) {
		printf("Doing galois_composite_w32_region_mult_k2 correctness test.\n");
		ib1 = (unsigned int *) cb1;
		ib2 = (unsigned int *) cb2;
		ib3 = (unsigned int *) cb3;
		for (x = 0; x < 10; x++) {
			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_composite_w32_region_mult_k2((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				printer = 1;
				if (galois_composite_multiply_k2(ib1[i], elt, w) != ib3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in ib3\n", 
							i, ib1[i], elt, galois_composite_multiply_k2(ib1[i], elt, w), ib3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_composite_w32_region_mult_k2((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			elt = galois_composite_divide_k2(1, elt, w);
			galois_composite_w32_region_mult_k2((unsigned char *) ib3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib1[i] != ib3[i]) {
					printf("Failed test (r2 == NULL): Byte %d (0x%x): %u != %u\n", i, ib3+i, ib1[i], ib3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48());
			for (i = 0; i < BUFSIZE/4; i++) ib3[i] = ib2[i];
			galois_composite_w32_region_mult_k2((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 1);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib3[i] != (ib2[i] ^ galois_composite_multiply_k2(ib1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  ib3 = %u\n", 
							i, ib1[i], elt, ib2[i], (galois_composite_multiply_k2(ib1[i], elt, w)^ib2[i]), ib3[i]);
					exit(1);
				}
			}
		}
		galois_composite_w32_region_mult_k2((unsigned char *) ib1, 0, BUFSIZE, (unsigned char *) ib3, 0);
		for (i = 0; i < BUFSIZE/4; i++) {
			if (ib3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, ib3[i]);
				exit(1);
			}
		}
		printf("Passed galois_composite_w32_region_mult_k2 correctness test.\n");
		printf("\n");
	}

	if (w == 32 && mtype == DEFAULT) {
		printf("Doing galois_w32_region_multiply correctness test.\n");
		ib1 = (unsigned int *) cb1;
		ib2 = (unsigned int *) cb2;
		ib3 = (unsigned int *) cb3;
		for (x = 0; x < 10; x++) {
			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_w32_region_multiply((char *) ib1, elt, BUFSIZE, (char *) ib3, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				printer = 1;
				if (galois_shift_multiply(ib1[i], elt, w) != ib3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in ib3\n", 
							i, ib1[i], elt, galois_shift_multiply(ib1[i], elt, w), ib3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_w32_region_multiply((char *) ib1, elt, BUFSIZE, (char *) ib3, 0);
			elt = galois_shift_divide(1, elt, w);
			galois_w32_region_multiply((char *) ib3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib1[i] != ib3[i]) {
					printf("Failed test (r2 == NULL): Byte %d (0x%x): %u != %u\n", i, ib3+i, ib1[i], ib3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48());
			for (i = 0; i < BUFSIZE/4; i++) ib3[i] = ib2[i];
			galois_w32_region_multiply((char *) ib1, elt, BUFSIZE, (char *) ib3, 1);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib3[i] != (ib2[i] ^ galois_shift_multiply(ib1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  ib3 = %u\n", 
							i, ib1[i], elt, ib2[i], (galois_shift_multiply(ib1[i], elt, w)^ib2[i]), ib3[i]);
					exit(1);
				}
			}
		}
		galois_w32_region_multiply((char *) ib1, 0, BUFSIZE, (char *) ib3, 0);
		for (i = 0; i < BUFSIZE/4; i++) {
			if (ib3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, ib3[i]);
				exit(1);
			}
		}
		printf("Passed galois_w32_region_multiply correctness test.\n");
		printf("\n");
	}

if (w == 32 && mtype == LAZYSPLIT) {
		printf("Doing galois_w32_lazy_split_region_multiply correctness test.\n");
		ib1 = (unsigned int *) cb1;
		ib2 = (unsigned int *) cb2;
		ib3 = (unsigned int *) cb3;
		for (x = 0; x < 10; x++) {
			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_w32_lazy_split_region_multiply((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				printer = 1;
				if (galois_single_multiply(ib1[i], elt, w) != ib3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in ib3\n",
							i, ib1[i], elt, galois_single_multiply(ib1[i], elt, w), ib3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_w32_lazy_split_region_multiply((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			elt = galois_single_divide(1, elt, w);
			galois_w32_lazy_split_region_multiply((unsigned char *) ib3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib1[i] != ib3[i]) {
					printf("Failed test (r2 == NULL): Byte %d (0x%x): %u != %u\n", i, ib3+i, ib1[i], ib3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48());
			for (i = 0; i < BUFSIZE/4; i++) ib3[i] = ib2[i];
			galois_w32_lazy_split_region_multiply((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 1);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib3[i] != (ib2[i] ^ galois_single_multiply(ib1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  ib3 = %u\n",
							i, ib1[i], elt, ib2[i], (galois_single_multiply(ib1[i], elt, w)^ib2[i]), ib3[i]);
					exit(1);
				}
			}
		}
		galois_w32_lazy_split_region_multiply((unsigned char *) ib1, 0, BUFSIZE, (unsigned char *) ib3, 0);
		for (i = 0; i < BUFSIZE/4; i++) {
			if (ib3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, ib3[i]);
				exit(1);
			}
		}
		printf("Passed galois_w32_lazy_split_region_multiply correctness test.\n");
		printf("\n");
	}

	if (w == 32 && mtype == TEST) {
		printf("Doing galois_w32_test_split_region_multiply correctness test.\n");
		ib1 = (unsigned int *) cb1;
		ib2 = (unsigned int *) cb2;
		ib3 = (unsigned int *) cb3;
		for (x = 0; x < 10; x++) {
			/* First, test with r2 specified, and add = 0 */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_w32_test_split_region_multiply((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				printer = 1;
				if (galois_single_multiply(ib1[i], elt, w) != ib3[i]) {
					printf("Failed test (r2 != NULL, add == 0). Word %u: %u * %u = %u, but it is %u in ib3\n",
							i, ib1[i], elt, galois_single_multiply(ib1[i], elt, w), ib3[i]);
					exit(1);
				}
			}

			/* Next, test with r2 = NULL */
			for (elt = 0; elt == 0; elt = lrand48());
			galois_w32_test_split_region_multiply((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 0);
			elt = galois_single_divide(1, elt, w);
			galois_w32_test_split_region_multiply((unsigned char *) ib3, elt, BUFSIZE, NULL, 0);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib1[i] != ib3[i]) {
					printf("Failed test (r2 == NULL): Byte %d (0x%x): %u != %u\n", i, ib3+i, ib1[i], ib3[i]);
					exit(1);
				}
			}

			/* Finally, test with r2 specified, and add = 1 */

			for (elt = 0; elt == 0; elt = lrand48());
			for (i = 0; i < BUFSIZE/4; i++) ib3[i] = ib2[i];
			galois_w32_test_split_region_multiply((unsigned char *) ib1, elt, BUFSIZE, (unsigned char *) ib3, 1);
			for (i = 0; i < BUFSIZE/4; i++) {
				if (ib3[i] != (ib2[i] ^ galois_single_multiply(ib1[i], elt, w))) {
					printf("Failed test (r2 != NULL && add == 1) Byte %u: (%u * %u) ^ %u = %u.  ib3 = %u\n",
							i, ib1[i], elt, ib2[i], (galois_single_multiply(ib1[i], elt, w)^ib2[i]), ib3[i]);
					exit(1);
				}
			}
		}
		galois_w32_test_split_region_multiply((unsigned char *) ib1, 0, BUFSIZE, (unsigned char *) ib3, 0);
		for (i = 0; i < BUFSIZE/4; i++) {
			if (ib3[i] != 0) {
				printf("Failed multiply by zero test.  Byte %d = %d\n", i, ib3[i]);
				exit(1);
			}
		}
		printf("Passed galois_w32_test_split_region_multiply correctness test.\n");
		printf("\n");
	}


  if (!(mtype == TEST || mtype == LAZYSPLIT || mtype == COMP22)) {
	printf("Speed Test #1: 10 Seconds of Multiply operations\n");
	t0 = time(0);
	gettimeofday(&t1, &tz);
	total = 0;
	while (time(0) - t0 < 10) {
		switch (mtype) {
			case DEFAULT: for (i = 0; i < S_BUFSIZE; i++) galois_single_multiply(b1[i], b2[i], w); break;
			case MULT:    for (i = 0; i < S_BUFSIZE; i++) galois_multtable_multiply(b1[i], b2[i], w); break;
			case LOG:     for (i = 0; i < S_BUFSIZE; i++) galois_logtable_multiply(b1[i], b2[i], w); break;
			case SHIFT:   for (i = 0; i < S_BUFSIZE; i++) galois_shift_multiply(b1[i], b2[i], w); break;
			case SPLITW8:   for (i = 0; i < S_BUFSIZE; i++) galois_split_w8_multiply(b1[i], b2[i]); break;
			case COMP2:   for (i = 0; i < S_BUFSIZE; i++) galois_composite_multiply_k2(b1[i], b2[i], w); break;
			case COMP4:   for (i = 0; i < S_BUFSIZE; i++) galois_composite_multiply_k4(b1[i], b2[i], w); break;
			case LAZYTABLE8: for (i = 0; i < S_BUFSIZE; i++) galois_multtable_multiply(b1[i], b2[i], w); break;
			case LAZYTABLE16: for (i = 0; i < S_BUFSIZE; i++) galois_logtable_multiply(b1[i], b2[i], w); break;
		}
		total++;
	}
	gettimeofday(&t2, &tz);

	tsec = 0;
	tsec += t2.tv_usec;
	tsec -= t1.tv_usec;
	tsec /= 1000000.0;
	tsec += t2.tv_sec;
	tsec -= t1.tv_sec;
	total *= S_BUFSIZE;
	printf("Speed Test #1: %.5lf Mega Multiplies per second\n", total/tsec/1024.0/1024.0);

	printf("Speed Test #2: 10 Seconds of Divide operations\n");
	t0 = time(0);
	gettimeofday(&t1, &tz);
	total = 0;
	while (time(0) - t0 < 10) {
		switch (mtype) {
			case DEFAULT: for (i = 0; i < S_BUFSIZE; i++) galois_single_divide(b1[i], b2[i], w); break;
			case MULT:    for (i = 0; i < S_BUFSIZE; i++) galois_multtable_divide(b1[i], b2[i], w); break;
			case LOG:     for (i = 0; i < S_BUFSIZE; i++) galois_logtable_divide(b1[i], b2[i], w); break;
			case SHIFT:   for (i = 0; i < S_BUFSIZE; i++) galois_shift_divide(b1[i], b2[i], w); break;
			case SPLITW8:   for (i = 0; i < S_BUFSIZE; i++) galois_shift_divide(b1[i], b2[i], w); break;
			case COMP2:   for (i = 0; i < S_BUFSIZE; i++) galois_composite_divide_k2(b1[i], b2[i], w); break;
			case COMP4:   for (i = 0; i < S_BUFSIZE; i++) galois_composite_divide_k4(b1[i], b2[i], w); break;
			case LAZYTABLE8:    for (i = 0; i < S_BUFSIZE; i++) galois_multtable_divide(b1[i], b2[i], w); break;
			case LAZYTABLE16:     for (i = 0; i < S_BUFSIZE; i++) galois_logtable_divide(b1[i], b2[i], w); break;
		}
		total++;
	}
	gettimeofday(&t2, &tz);

	tsec = 0;
	tsec += t2.tv_usec;
	tsec -= t1.tv_usec;
	tsec /= 1000000.0;
	tsec += t2.tv_sec;
	tsec -= t1.tv_sec;
	total *= S_BUFSIZE;
	printf("Speed Test #2: %.5lf Mega Divides per second\n", total/tsec/1024.0/1024.0);
	}


	//if (!(mtype == DEFAULT || mtype == COMP2 || mtype == COMP4)) exit(0);

	printf("\n");

	if (w == 8 && mtype == COMP2) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");
		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()%top) ;
					if (i == 0) {
						galois_composite_w08_region_mult_k2(cb1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_composite_w08_region_mult_k2(cb1, elt, BUFSIZE, cb3, 0); 
					} else {
						galois_composite_w08_region_mult_k2(cb1, elt, BUFSIZE, cb3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}


	}

	if (w == 8 && mtype == DEFAULT) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");
		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()%top) ;
					if (i == 0) {
						galois_w08_region_multiply((char *) cb1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_w08_region_multiply((char *) cb1, elt, BUFSIZE, (char *) cb3, 0); 
					} else {
						galois_w08_region_multiply((char *) cb1, elt, BUFSIZE, (char *) cb3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}

	if (w == 8 && mtype == LOG) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");
		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()%top) ;
					if (i == 0) {
						galois_w08_log_region_multiply((unsigned char *) cb1, elt, BUFSIZE, NULL, 0);          
					} else if (i == 1) {
						galois_w08_log_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 0);
					} else {            
						galois_w08_log_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 1);
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}


	if (w == 8 && mtype == LAZYTABLE8) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");
		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()%top) ;
					if (i == 0) {
						galois_w08_lazytable_region_multiply((unsigned char *) cb1, elt, BUFSIZE, NULL, 0);
					} else if (i == 1) {
						galois_w08_lazytable_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 0);
					} else {
						galois_w08_lazytable_region_multiply((unsigned char *) cb1, elt, BUFSIZE, (unsigned char *) cb3, 1);
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}


	if (w == 16 && mtype == COMP2) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");

		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()%top) ;
					if (i == 0) {
						galois_composite_w16_region_mult_k2((unsigned char *) sb1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_composite_w16_region_mult_k2((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 0); 
					} else {
						galois_composite_w16_region_mult_k2((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}

	if (w == 16 && mtype == DEFAULT) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");

		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()%top) ;
					if (i == 0) {
						galois_w16_region_multiply((char *) sb1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_w16_region_multiply((char *) sb1, elt, BUFSIZE, (char *) sb3, 0); 
					} else {
						galois_w16_region_multiply((char *) sb1, elt, BUFSIZE, (char *) sb3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}

	if (w == 16 && mtype == LAZYTABLE16) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");

		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()%top) ;
					if (i == 0) {
						galois_w16_lazytable_region_multiply((unsigned char *) sb1, elt, BUFSIZE, NULL, 0);
					} else if (i == 1) {
						galois_w16_lazytable_region_multiply((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 0);
					} else {
						galois_w16_lazytable_region_multiply((unsigned char *) sb1, elt, BUFSIZE, (unsigned char *) sb3, 1);
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}

if (w == 32 && mtype == COMP22) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");

		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()) ;
					if (i == 0) {
						galois_w32_composite_region_mult_k22((unsigned char *)ib1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_w32_composite_region_mult_k22((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 0); 
					} else if (i == 2) {
						galois_w32_composite_region_mult_k22((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}

	if (w == 32 && mtype == COMP4) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");

		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()) ;
					if (i == 0) {
						galois_composite_w32_region_mult_k4((unsigned char *)ib1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_composite_w32_region_mult_k4((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 0); 
					} else if (i == 2) {
						galois_composite_w32_region_mult_k4((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}
	if (w == 32 && mtype == COMP2) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");

		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()) ;
					if (i == 0) {
						galois_composite_w32_region_mult_k2((unsigned char *)ib1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_composite_w32_region_mult_k2((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 0); 
					} else if (i == 2) {
						galois_composite_w32_region_mult_k2((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}
	if (w == 32 && mtype == DEFAULT) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");

		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()) ;
					if (i == 0) {
						galois_w32_region_multiply((char *) ib1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_w32_region_multiply((char *) ib1, elt, BUFSIZE, (char *) ib3, 0); 
					} else if (i == 2) {
						galois_w32_region_multiply((char *) ib1, elt, BUFSIZE, (char *) ib3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}

if (w == 32 && mtype == TEST) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");

		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()) ;
					if (i == 0) {
						galois_w32_test_split_region_multiply((unsigned char *)ib1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_w32_test_split_region_multiply((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 0); 
					} else if (i == 2) {
						galois_w32_test_split_region_multiply((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}

if (w == 32 && mtype == LAZYSPLIT) {
		printf("Doing 10 seconds worth of region_multiplies - Three tests:\n");
		printf("   Test 0: Overwrite initial region\n");
		printf("   Test 1: Products to new region\n");
		printf("   Test 2: XOR products into second region\n\n");

		for (i = 0; i < 3; i++) {
			t0 = time(0);
			gettimeofday(&t1, &tz);
			total = 0;
			while (time(0) - t0 < 10) {
				for (x = 0; x < 10; x++) {
					for (elt = 0; elt == 0; elt = lrand48()) ;
					if (i == 0) {
						galois_w32_lazy_split_region_multiply((unsigned char *)ib1, elt, BUFSIZE, NULL, 0); 
					} else if (i == 1) {
						galois_w32_lazy_split_region_multiply((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 0); 
					} else if (i == 2) {
						galois_w32_lazy_split_region_multiply((unsigned char *)ib1, elt, BUFSIZE, (unsigned char *)ib3, 1); 
					}
					total += BUFSIZE;
				}
			}
			gettimeofday(&t2, &tz);

			tsec = 0;
			tsec += t2.tv_usec;
			tsec -= t1.tv_usec;
			tsec /= 1000000.0;
			tsec += t2.tv_sec;
			tsec -= t1.tv_sec;
			printf("   Test %u: %.5lf Megabytes of Multiplies per second\n", i, total/tsec/1024.0/1024.0);
		}
	}

return 0;
}
